package view;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Shape;
import java.awt.geom.CubicCurve2D;

import common.Utils;

import model.DrawObject;

public class ViewBezier extends ViewObject
{
	// these are the coefficients for the parametric functions of a cubic curve;
	private double a, b, c, d, e, f, g, h;
	
	final private double[][] Bz = { {-1,  3, -3, 1}, 
									{ 3, -6,  3, 0},
									{-3,  3,  0, 0},
									{ 1,  0,  0, 0}	};
	
	
	public ViewBezier(DrawObject obj, Graphics g)
	{
		super(obj, g);
		calcCoefficiencts();
	}

	public ViewBezier(DrawObject obj, Graphics2D g2)
	{
		super(obj, g2);
		calcCoefficiencts();
	}


	@Override
	public void Draw(Graphics g)
	{
		super.Draw(g);
		
		Graphics2D g2 = (Graphics2D)g;
		
		Color c = new Color(dObj.getRed(), dObj.getGreen(), dObj.getBlue());
		g2.setColor(c);
		
		g2.setStroke(new BasicStroke( (float)dObj.getThickness() ));
		
		Shape bez = new CubicCurve2D.Float(	dObj.getX1(), 
											dObj.getY1(), 
											dObj.getX2(), 
											dObj.getY2(), 
											dObj.getX3(), 
											dObj.getY3(), 
											dObj.getX4(), 
											dObj.getY4()  );
		g2.draw(bez);	

//		// For temporary testing purposes
//		g2.setColor( new Color(255,0,0) );
//		g2.setStroke( new BasicStroke(1) );
//		
//		double inc = 1.0/1000.0;
//		int x, y;
//		for (double t=0; t<=1; t+=inc)
//		{
//			x = pFuncX(t);
//			y = pFuncY(t);
//			g2.drawLine(x, y, x, y);
//		}
//		
//		g2.drawLine(250, 200, 250, 200);
	
	}

	@Override
	public int pFuncX(double t)
	{	
		// x = a*t^3 + b*t^2 + c*t + d
		return (int)( a*Math.pow(t, 3) + b*Math.pow(t, 2) + c*t + d );
	}

	@Override
	public int pFuncY(double t)
	{
		// y = e*t^3 + f*t^2 + g*t + h
		return (int)( e*Math.pow(t, 3) + f*Math.pow(t, 2) + g*t + h );
	}

	@Override
	public BoundBox getBounds(boolean padded)
	{
		int minX, minY, maxX, maxY;
		
		minX = dObj.getX1();
		minX = ( dObj.getX2() < minX )? dObj.getX2() : minX;
		minX = ( dObj.getX3() < minX )? dObj.getX3() : minX;
		minX = ( dObj.getX4() < minX )? dObj.getX4() : minX;
		
		minY = dObj.getY1();
		minY = ( dObj.getY2() < minY )? dObj.getY2() : minY;
		minY = ( dObj.getY3() < minY )? dObj.getY3() : minY;
		minY = ( dObj.getY4() < minY )? dObj.getY4() : minY;
		
		maxX = dObj.getX1();
		maxX = ( dObj.getX2() > maxX )? dObj.getX2() : maxX;
		maxX = ( dObj.getX3() > maxX )? dObj.getX3() : maxX;
		maxX = ( dObj.getX4() > maxX )? dObj.getX4() : maxX;
		
		maxY = dObj.getY1();
		maxY = ( dObj.getY2() > maxY )? dObj.getY2() : maxY;
		maxY = ( dObj.getY3() > maxY )? dObj.getY3() : maxY;
		maxY = ( dObj.getY4() > maxY )? dObj.getY4() : maxY;
		
		int padding = (padded)? Utils.MIN_DIST : 0;
		
		BoundBox box = new BoundBox();
		box.setX(minX - padding);
		box.setY(minY - padding);
		box.setWidth(maxX - minX + padding*2);
		box.setHeight(maxY - minY + padding*2);
		
		return box;
	}

	@Override
	public boolean containsPoint(Point p)
	{
		if (!getBounds(true).contains(p))
			return false;
		
		if (this.distSqToShape(p) <= Utils.MIN_DIST_SQ)
			return true;
			
		return false;
	}

	
	public static double[][] matrixMult (double[][] m1, double[][] m2)
	{
		int m1_h = m1.length;
		int m1_w = m1[0].length;
		int m2_h = m2.length;
		int m2_w = m2[0].length;
		
		double[][] m3 = new double[0][0];
		
		if ( m1_w != m2_h )
		{
			System.out.println("Those matrices CANNOT be multiplied!");
			return m3;
		}
		
		int h = m1_h;
		int w = m2_w;
		m3 = new double[h][w];
		
		int cols = w;
		int rows = h;
		for (int c=0; c<cols; c++)
			for (int r=0; r<rows; r++)
				for (int c2=0; c2<m1_w; c2++)
				{
					double m1_t = m1[r][c2];
					double m2_t = m2[c2][c];
					m3[r][c] = m3[r][c] + m1_t*m2_t;
				}
		
		return m3;
	}
	
	private void calcCoefficiencts()
	{
		double[][] coef = matrixMult( getPointMatrix() , Bz);
		
		a=coef[0][0];
		b=coef[0][1];
		c=coef[0][2];
		d=coef[0][3];
		
		e=coef[1][0];
		f=coef[1][1];
		g=coef[1][2];
		h=coef[1][3];
	}
	
	private double[][] getPointMatrix()
	{
		double[][] m = {	{dObj.getX1(), dObj.getX2(), dObj.getX3(), dObj.getX4()},
							{dObj.getY1(), dObj.getY2(), dObj.getY3(), dObj.getY4()}	};
		
		return m;
	}
	
}












